package com.enlorenz.core.channel.socket.imp.shortconnection;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import com.enlorenz.common.util.ReflectionUtils;
import com.enlorenz.common.util.SocketUtils;
import com.enlorenz.common.util.StreamUtils;
import com.enlorenz.common.util.TimeUtils;
import com.enlorenz.core.base.IReqResMessageHandle;
import com.enlorenz.core.channel.socket.common.reader.ISocketReader;
import com.enlorenz.core.channel.socket.common.translate.BytesMessageTransformer;
import com.enlorenz.core.channel.socket.common.translate.IMessageBytesTransformer;
import com.enlorenz.core.channel.socket.common.writer.ISocketWriter;
import com.enlorenz.core.engine.exception.EngineControlException;
import com.enlorenz.core.engine.imp.thread.quick.AbstractQuickControlThread;

/**
 * 基础的服务通道
 * @author Karma
 *
 */
public class SocketServerChannel extends AbstractQuickControlThread{
	private ServerSocket server;
	//监听端口
	protected Integer listenPort;
	//读取器
	private ISocketReader reader;
	//写出器
	private ISocketWriter writer;
	//接收消息处理器
	private IReqResMessageHandle recvMsgHandle;
	//消息转换器,如果没有传入值，则使用默认的转换器
	private IMessageBytesTransformer messageBytesTransformer
		=new BytesMessageTransformer();
	private int soTimeout=(int)TimeUtils.MINUTE_MILLI*5;
	/**
	 * 启动Socket服务
	 */
	protected void startEngine() throws EngineControlException {
		try {
			//启动服务
			socketServerStart();
		} catch (IOException e) {
			throw new EngineControlException(this.getName(),e);
		}
		super.startEngine();
	}
	
	/**
	 * socket服务启动
	 * @throws IOException
	 */
	private void socketServerStart() throws IOException {
		try {
			server=new ServerSocket(listenPort);
			server.setSoTimeout(soTimeout);
		} catch (IOException e) {
			close();
			throw e;
		}
	}
	
	/**
	 * 关闭打开的链接
	 */
	private void close() {
		//关闭选择器
		SocketUtils.closeSocketServer(server);
		server = null;
	}
	
	/**
	 * 关闭Socket服务
	 */
	@Override
	protected void shutdownEngine() throws EngineControlException {
		//关闭选择器和服务
		close();
		//调用父类的关闭
		super.shutdownEngine();
	}
	
	@Override
	protected void handle() throws Exception {
		Socket socket=server.accept();
		ServerThread serverThread=new ServerThread();
		serverThread.setSocket(socket);
		serverThread.start();
	}
	
	private class ServerThread extends Thread{
		private Socket socket; 
		
		public void run(){
			handleMessageImp(socket);
		}
		public void setSocket(Socket socket) {
			this.socket = socket;
		}
	}
	
	/**
	 * 发送消息的具体实现类
	 * @param is 输入流
	 * @param os 输出流
	 * @param message 待发送的消息
	 * @return 接收到的消息
	 * @throws Exception 发送中产生的异常
	 */
	protected void handleMessageImp(Socket socket){
		InputStream is=null;
		OutputStream os=null;
		try{
			//克隆一份读取器
			ISocketReader cloneSocketReader=(ISocketReader)
					ReflectionUtils.copy2NewObject(reader);
			
			//获取输入流
			is=socket.getInputStream();
			cloneSocketReader.setInputStream(is);
			byte [] recvData=cloneSocketReader.read();
			//将byte转化为内部消息
			Object resultMessage=messageBytesTransformer.
				bytes2Message(recvData);
			
			Object res=recvMsgHandle.reqResMsgHandle(resultMessage);
			
			//将消息转化为字节流
			byte [] data=messageBytesTransformer.message2Bytes(res);
			
			//克隆一份写出器
			ISocketWriter cloneSocketWriter=(ISocketWriter)
					ReflectionUtils.copy2NewObject(writer);
			
			//获取输出流
			os=socket.getOutputStream();
			//写出字节流
			cloneSocketWriter.write(os,data);
		}catch (Exception e) {
			throw new RuntimeException(e);
		}finally{
			//关闭输入流
			StreamUtils.closeStream(is);
			//关闭输出流
			StreamUtils.closeStream(os);
			//关闭socket链接
			SocketUtils.closeSocket(socket);
		}
	}

	public void setListenPort(Integer listenPort) {
		this.listenPort = listenPort;
	}

	public void setReader(ISocketReader reader) {
		this.reader = reader;
	}

	public void setWriter(ISocketWriter writer) {
		this.writer = writer;
	}

	public void setRecvMsgHandle(IReqResMessageHandle recvMsgHandle) {
		this.recvMsgHandle = recvMsgHandle;
	}

	public void setMessageBytesTransformer(
			IMessageBytesTransformer messageBytesTransformer) {
		this.messageBytesTransformer = messageBytesTransformer;
	}

	public void setSoTimeout(int soTimeout) {
		this.soTimeout = soTimeout;
	}
	
}
